﻿using InfoPathHelpers.CodeGeneration.Core;
using InfoPathHelpers.TemplateExplorer;
using Microsoft.Office.InfoPath;
using System;
using System.CodeDom;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.XPath;

namespace InfoPathHelpers.CodeGeneration
{
    public class ConstantsGenerator : CodeDomCSharpGenerator
    {
        public static void Generate(FormContext formContext)
        {
            // Use the namespace of the form so it can work as a partial class.
            var FormNamespace = new CodeNamespace(formContext.CodeNamespace + ".Constants");

            // Add the namespace to the compile unit.
            var TargetUnit = new CodeCompileUnit();
            TargetUnit.Namespaces.Add(FormNamespace);

            var ManifestExplorer = new ManifestExplorer(formContext);

            // Add a static class for each type of string variable.
            FormNamespace.Types.Add(CreateUsersClass(ManifestExplorer));
            FormNamespace.Types.Add(CreateFileConnectionsClass(ManifestExplorer));
            FormNamespace.Types.Add(CreateEmailConnectionsClass(ManifestExplorer));
            FormNamespace.Types.Add(CreateViewsClass(ManifestExplorer));
            FormNamespace.Types.Add(CreateDataSourceFilesClass(ManifestExplorer));

            // Generate the output file.
            string OutputFileName = Directory.GetCurrentDirectory().Replace(@"bin\Debug", "Constants.Generated.cs");
            GenerateOutputFile(OutputFileName, TargetUnit);
        }

        private static CodeMemberField CreateConstString(string value)
        {
            var ConstField = new CodeMemberField(typeof(string), CreateValidIdentifier(value));
            ConstField.Attributes = MemberAttributes.Const | MemberAttributes.Public;
            ConstField.InitExpression = new CodePrimitiveExpression(value);
            return ConstField;
        }

        private static CodeMemberField CreateConstString(string name, string value)
        {
            var ConstField = new CodeMemberField(typeof(string), CreateValidIdentifier(name));
            ConstField.Attributes = MemberAttributes.Const | MemberAttributes.Public;
            ConstField.InitExpression = new CodePrimitiveExpression(value);
            return ConstField;
        }

        private static CodeTypeDeclaration CreateViewsClass(ManifestExplorer manifestExplorer)
        {
            var ViewsClass = new CodeTypeDeclaration("Views");
            ViewsClass.IsClass = true;
            ViewsClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;

            foreach (var View in manifestExplorer.GetViews())
            {
                ViewsClass.Members.Add(CreateConstString(View.Name));
            }

            return ViewsClass;
        }

        private static CodeTypeDeclaration CreateDataSourceFilesClass(ManifestExplorer manifestExplorer)
        {
            var DataSourceFilesClass = new CodeTypeDeclaration("DataSourceFiles");
            DataSourceFilesClass.IsClass = true;
            DataSourceFilesClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;

            foreach (var XmlFileAdapter in manifestExplorer.GetXmlFileAdapters())
            {
                if (!XmlFileAdapter.IsIncludedInTemplate)
                {
                    DataSourceFilesClass.Members.Add(CreateConstString(XmlFileAdapter.Name, XmlFileAdapter.Path));
                }
            }

            return DataSourceFilesClass;
        }

        private static CodeTypeDeclaration CreateFileConnectionsClass(ManifestExplorer manifestExplorer)
        {
            var FileConnectionsClass = new CodeTypeDeclaration("FileConnections");
            FileConnectionsClass.IsClass = true;
            FileConnectionsClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;

            foreach (var XmlFileAdapter in manifestExplorer.GetXmlFileAdapters())
            {
                FileConnectionsClass.Members.Add(CreateConstString(XmlFileAdapter.Name, XmlFileAdapter.Name));
            }

            return FileConnectionsClass;
        }

        private static CodeTypeDeclaration CreateEmailConnectionsClass(ManifestExplorer manifestExplorer)
        {
            var EmailConnectionsClass = new CodeTypeDeclaration("EmailConnections");
            EmailConnectionsClass.IsClass = true;
            EmailConnectionsClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;

            foreach (var EmailAdapter in manifestExplorer.GetEmailAdapters())
            {
                EmailConnectionsClass.Members.Add(CreateConstString(EmailAdapter.Name));
            }
            
            return EmailConnectionsClass;
        }

        private static CodeTypeDeclaration CreateUsersClass(ManifestExplorer manifestExplorer)
        {
            var UsersClass = new CodeTypeDeclaration("Users");
            UsersClass.IsClass = true;
            UsersClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;

            var UserRoleCollection = manifestExplorer.GetUserRoles();

            foreach (var UserRole in UserRoleCollection.Roles)
            {
                UsersClass.Members.Add(CreateConstString(UserRole.Name));
            }

            return UsersClass;
        }
    }
}
